package nige.jar.classe;

import java.io.File;
import java.util.Vector;

import nige.utils.object.Attente;

/**
 * Classe permettant de lister les fichiers Jar et de les scanner.
 * Etend la classe thread pour accelerer les traitements
 * <br />- AllThread : Liste de tous les thread lance
 * <br />- dossier : Dossier scanne en cours
 * <br />- classe : Classe a trouver
 * <br />- jf : Liste des jar trouve comme contenant la classe
 * @author Nicolas Genevaux
 * 
 * DEPTH   2
 *       Object
 *       Thread
 * CALLEE  1
 *       Principale
 * 
 * 14-02-2008   Nicolas Genevaux      v.0.0.1
 */
public class ListeFichierJar extends Thread {

  /**
   * AllThread : Liste de tous les thread lance
   */
  private Vector<Object> allThread = new Vector<Object>(0);
  /**
   * dossier : Dossier scanne en cours
   */
  private String dossier = "";
  /**
   * classe : Classe a trouver
   */
  private String classe = "";
  /**
   * jf : Liste des jar trouve comme contenant la classe
   */
  private JarFound jf = new JarFound();
  
  /**
   * Constructeur de la classe
   * @param odossier Dossier a scanner
   * @param oclasse Nom de la classe a trouver
   * @param ojf Vecteur contenant le resultat de l analyse
   */
  public ListeFichierJar(String odossier, String oclasse,JarFound ojf) {
    jf = ojf;
    classe = oclasse;
    dossier = odossier;
  }
  
  /**
   * Action a realiser par le thread.
   * Le thread liste tous les fichiers a traiter
   * Si une erreur intervient, alors il sort de la boucle
   * @Override La methode run du thread
   */
  public void run() {
    listeToutFichierJar(this.dossier);
  }
  
  /**
   * Cherche les fichiers jars dans le dossier dossier. Lance des 
   * thread a chaque dossier.
   * Boucle sur le nombre de thread fini et le nombre de thread 
   * lance pour eviter
   * que plus de 1000 threads soient lances.
   * Fichclasse retrouve les classe se terminant par *.
   * Test si le fichier en cours correspond a la classe (dans le cas 
   * d un classpath)
   * Incremente les dossier analyse et les thread lance.
   * Boucle sur la liste des fichiers trouves dans le dossier.
   * @param dossier Dossier a scanner
   */
  private boolean listeToutFichierJar(String dossier) {
    while((jf.getThreadEnded()+jf.getThreadLaunch())>1000) {
      Attente.perform(1000);
    }
    String fichClasse = dossier.toString().
        replaceAll("/",".").
          replace("\\",".")+".*";
    if(
        (fichClasse.indexOf(classe)==
          (fichClasse.length()-(classe).length()))&&
        (fichClasse.indexOf(classe)>-1)) {
      jf.getAllJars().add(dossier);
    }
    jf.setDossierAnalyse(jf.getDossierAnalyse()+1);
    jf.setThreadLaunch(jf.getThreadLaunch()+1);
    Object[] listeFile = (new File(dossier)).listFiles();
    int i = 0;
    if(listeFile!=null) {
      for(i=0;i<listeFile.length;i++) {
        loopsVerification(listeFile,fichClasse,i);
      }
    }
    jf.setThreadEnded(jf.getThreadEnded()-1);
    return true;
  }
  
  /**
   * Instruction bouclee qui verifie que le fichier 
   * scanne est un dossier
   * Si le fichier scanne est undossier, alors on relance 
   * un thread pour scanner le
   * dossier en cours.
   * Sinon, c est un fichier et on verifie ce fichier.
   * @param listeFile Liste des fichier a scanner
   * @param fichClasse Nom de la classe a trouver
   * @param i Iteration
   */
  private void loopsVerification(Object[] listeFile,
      String fichClasse,int i) {
    File fich = new File(listeFile[i].toString());
    if(fich.isDirectory()) {
      ListeFichierJar lfj = 
        new ListeFichierJar(fich.toString(),classe,jf);
      lfj.start();
      allThread.add(lfj);
    }
    else {
      verifFichierJar(fich,fichClasse);
    }
  }
  
  /**
   * Fonction qui verifie dans le fichier jar si la classe 
   * est contenu dans ce fichier.
   * Si le fichier est un fichier, on lance le thread de scan des 
   * fichiers jar.
   * Sinon, on teste que le fichier correspond ou non a une classe 
   * (classpath)
   * @param fich Objet de type fichier qui pointe vers le fichier jar
   * @param fichClasse Nom de la classe a trouver
   */
  private void verifFichierJar(File fich,String fichClasse) {
    jf.setFichierTotal(jf.getFichierTotal()+1);
    if((fich.toString().indexOf(".jar"))==
      fich.toString().length()-".jar".length()) {
      TrouveClasse tc = 
        new TrouveClasse(fich.toString(),classe,jf);
      tc.start();
      allThread.add(tc);
    }
    else {
      fichClasse = fich.toString().replaceAll("/",".").
        replace("\\",".");
      verifExistClasse(fich,fichClasse);
    }
  }
  
  /**
   * Verifie que la classe existe qu un fichier 
   * correspond a la classe analyse
   * Si le fichier est egal avec la chaine de caratere 
   * .class a la fin (fichier class) ou
   * Si le fichier est egal avec la chaine de caratere 
   * .java a la fin (fichier java)
   * @param fich Object de type fichier qui pointe vers 
   * le fichier en question
   * @param fichClasse Nom de la classe a trouver
   */
  private void verifExistClasse(File fich,String fichClasse) {
    if(fichClasse.indexOf(classe)>=0) {
      if(
          (fichClasse.indexOf(classe+".class")==
            (fichClasse.length()-(classe+".class").
                length()) ) ||
          (fichClasse.indexOf(classe+".java")==
            (fichClasse.length()-(classe+".java").
                length())) ) {
        jf.getAllJars().add(fich);
      }
    }
  }

}
